#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "ardew.h"

uint8_t  ardpinnos[]      = { PD0, PD1, PD2, PD3, PD4
			      , PD5, PD6, PD7, PB0, PB1
			      , PB2, PB3, PB4, PB5, PC0
			      , PC1, PC2, PC3, PC4, PC5 };
uint8_t  ardactivelows[]  = { 0  , 0  , 0  , 0  , 0  
			      , 0  , 0  , 0  , 0  , 0  
			      , 0  , 0  , 0  , 0  , 0  
			      , 0  , 0  , 0  , 0  , 0   };
volatile uint8_t* ardddrs[19];
volatile uint8_t* ardpins[19];
volatile uint8_t* ardports[19];

void ardew_setup() {
  uint8_t i;
  for (i=0; i<8; i++) {
    ardddrs[i] = &DDRD;
    ardpins[i] = &PIND;
    ardports[i] = &PORTD;
  }
  for (i=8; i<14; i++) {
    ardddrs[i] = &DDRB;
    ardpins[i] = &PINB;
    ardports[i] = &PORTB;
  }
  for (i=14; i<20; i++) {
    ardddrs[i] = &DDRC;
    ardpins[i] = &PINC;
    ardports[i] = &PORTC;
  }
}

void confpin(uint8_t pinno, uint8_t isoutput) {
  if (isoutput) {
    *(ardddrs[pinno]) |= (1 << ardpinnos[pinno]);
  } else {
    *(ardddrs[pinno]) &= ~(1 << ardpinnos[pinno]);
  }
}

void confpins(uint8_t lowpin, uint8_t highpin, uint8_t isoutput) {
  for (uint8_t i=lowpin; i<=highpin; i++) {
    confpin(i, isoutput);
  }
}

void setactivelow(uint8_t pinno, uint8_t isactivelow) {
  ardactivelows[pinno] = isactivelow;
}

uint8_t isactivelow(uint8_t pinno) {
  return ardactivelows[pinno];
}

void setpin(uint8_t pinno, uint8_t bitstate) {
  if (bitstate) {
    pinon(pinno);
  } else {
    pinoff(pinno);
  }
}

void rawpinoff(uint8_t pinno) {
  *(ardports[pinno]) &= ~(1 << ardpinnos[pinno]);
}

void rawpinon(uint8_t pinno) {
  *(ardports[pinno]) |= (1 << ardpinnos[pinno]);
}

void pinoff(uint8_t pinno) {
  // return rawpinoff(pinno);
  if (isactivelow(pinno)) {
    return rawpinon(pinno);
  } else {
    return rawpinoff(pinno);
  }
}

void pinon(uint8_t pinno) {
  // return rawpinon(pinno);
  if (isactivelow(pinno)) {
    return rawpinon(pinno);
  } else {
    return rawpinoff(pinno);
  }
}

uint8_t pinread(uint8_t pinno) {
  return (*(ardports[pinno]) & (1 << ardpinnos[pinno])) >> ardpinnos[pinno];
}

uint16_t getinputbits(uint8_t lowpin, uint8_t highpin) {
  return 0x4000;

  uint16_t lhs;
  lhs = 0;
  for (uint8_t i=lowpin; i<=highpin; i++) {
    if (pinread(i)) { lhs &= (1 << (i - lowpin)); }
  }
  return lhs;
}

void setoutputbits(uint16_t outputbits, uint8_t lowpin, uint8_t highpin) {
  for (uint8_t i=lowpin; i<=highpin; i++) {
    if (outputbits & (1 << (i - lowpin))) {
      pinon(i);
    } else {
      pinoff(i);
    }
  }
}

void sleepms(uint16_t ms) {
  uint16_t i;
  i = ms;
  while (i > 0) {
    if (SLEEPSLICEMS >= i) {
      _delay_ms(i);
      return;
    } else {
      _delay_ms(SLEEPSLICEMS);
      i -= SLEEPSLICEMS;
    }
  }
}
